Pressidian
花园入口
笔记
项目
关于
实验室
GitHub
花园入口
笔记
项目
关于
实验室
GitHub

KNOWLEDGE PATHS

笔记库
当前位置
笔记库/前端/面试/代码/算法

CodeTop Top55

6 分钟阅读 · Note

目录树 578 篇

            • 5 最长回文子串 ⌚️
            • 牛客 101
            • 数组&字符串技巧
            • 算法题
            • CodeTop Top55
            • LeetCode Hot100
          • 面试-常考经典1
          • 面试-常考经典2
          • 面试-数组专项
        • 可投递企业
      • 前端技术栈
    • 笔记目录
    • CLAUDE.md
    • Vue 组件与 Render 函数

关联笔记 6

↗5 最长回文子串 ⌚️同一路径↗牛客 101同一路径↗数组&字符串技巧同一路径↗算法题同一路径↗LeetCode Hot100同一路径↗解析模板字符串共同主题
  • CodeTop Top55

CodeTop Top55

> Last Format Time:7/9/2026 23:46:20

越是靠前,题目的热度越高🔥(筛选条件 岗位:前端)

这里的题目的编号和LeetCode一致,与另一个文档相同的题目只有编号。 据我统计,岗位不限中,前80道题目全部做完,基本上可以覆盖前端常考的题目,前端做前55道就可以了。


3 无重复字符的最长子串 ⌚️

#双指针 #滑动窗口 https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/

var lengthOfLongestSubstring = function(s) {
    let ans = 0;
    let left = 0;
    const cnt = new Map(); // 维护从下标 left 到下标 right 的字符
    for (let right = 0; right < s.length; right++) {
        const c = s[right];
        cnt.set(c, (cnt.get(c) ?? 0) + 1);
        while (cnt.get(c) > 1) { // 窗口内有重复字母
            cnt.set(s[left], cnt.get(s[left]) - 1); // 移除窗口左端点字母
            left++; // 缩小窗口
        }
        ans = Math.max(ans, right - left + 1); // 更新窗口长度最大值
    }
    return ans;
};

165 比较版本号 ⌚️

#字符串 https://leetcode.cn/problems/compare-version-numbers/description/ 给你两个 版本号字符串 version1 和 version2 ,请你比较它们。版本号由被点 '.' 分开的修订号组成。修订号的值 是它 转换为整数 并忽略前导零。

比较版本号时,请按 从左到右的顺序 依次比较它们的修订号。如果其中一个版本字符串的修订号较少,则将缺失的修订号视为 0。

// 输入:version1 = "1.2", version2 = "1.10"
var compareVersion = function (version1, version2) {

    const a = version1.split(".");
    const b = version2.split(".");

    console.log(a, b)
    // [ '1', '2' ] [ '1', '10' ]

    const n = a.length, m = b.length;

    for (let i = 0; i < n || i < m; i++) {
        // 越界的可以用空值合并
        const ver1 = i < n ? parseInt(a[i]) : 0;
        const ver2 = i < m ? parseInt(b[i]) : 0;
        if (ver1 !== ver2) {
            return ver1 < ver2 ? -1 : 1;
        }
    }
    return 0;
};

88 合并两个有序数组

#双指针 https://leetcode.cn/problems/merge-sorted-array/description/

两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意: 最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

/**
 Do not return anything, modify nums1 in-place instead.
 */
function merge(nums1: number[], m: number, nums2: number[], n: number): void {
    // 不可以从左到右去覆盖nums1,会丢失后面的项,我们可以从右向左去覆盖

    let index1 = m - 1
    let index2 = n - 1
    let endOfNums1 = m + n - 1

    while (index2 >= 0) {
        if (nums1[index1] >= nums2[index2]) {
            nums1[endOfNums1] = nums1[index1]

            index1--
            endOfNums1--
        } else {
            nums1[endOfNums1] = nums2[index2]

            index2--
            endOfNums1--
        }
    }

    console.log(nums1)
    // 不需要返回值
};

20 有效括号

#栈 #简单 https://leetcode.cn/problems/valid-parentheses/description/


415 字符串相加 ⌚️

#双指针 https://leetcode.cn/problems/add-strings/description/


1 两数之和

#哈希表 https://leetcode.cn/problems/two-sum/description/


46 全排列

#回溯 https://leetcode.cn/problems/permutations/description/ 有点忘了,重新做一遍:

function permute(nums: number[]): number[][] {
    let ans = []
    let n = nums.length
    let path = Array(n).fill(0)
    let onPath = Array(n).fill(false)

    // 代表下标为i的位的选择
    function dfs(i) {
        if (i === n) {
            ans.push(path.slice())
            return
        }
        // 遍历nums中的每一项,将每种不在path中的值加入path 
        for (let j = 0; j < n; j++) {
            if (!onPath[j]) {
                path[i] = nums[j]

                // 加入后,再确定下一位
                onPath[j] = true
                dfs(i + 1)

                // 回溯
                onPath[j] = false
            }
        }
    }

    dfs(0)
    return ans
};

206 反转链表

#链表 https://leetcode.cn/problems/reverse-linked-list/

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function (head) {
    let cur = head
    
    // pre节点始终是头插法的头结点 
    let pre = null
	
    // 使用头插法
    while (cur) {
        // 保存当前节点的下一个
        const nxt = cur.next
		
        // 将当前节点放在pre节点的前面
        cur.next = pre
		
        // pre向前移动一个
        pre = cur
		
        // cur向后移动一个
        cur = nxt
    }
};

102 二叉树的层序遍历

#二叉树

const levelOrder = (root) => {
    if (root === null) return []
    const ans = []

    let cur = [root]

    while (cur.length) {
        const nxt = []
        const vals = []
        
        for (const node of cur) {
            vals.push(node.val)
            if (node.left) nxt.push(node.left)
            if (node.right) nxt.push(node.right)
        }
        cur = nxt
        ans.push(vals)
    }
    return ans
}

53 最大子数组和

#动态规划

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function (nums) {
    // dp[i] 表示长度为i的数组的最大子数和
    // dp[i] = Math.max(dp[i - 1], 0) + nums[i]
    // dp[i] = 0
    let n = nums.length
    let dp = Array(n).fill(0)
    dp[0] = nums[0]

    for (let i = 1; i < n; i++) {
        dp[i] = Math.max(dp[i - 1], 0) + nums[i]
    }

    return Math.max(...dp)
};

121 买卖股票的最佳时机

#贪心 https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function (prices) {
    // min表示当前价格前面的最小价格
    let min = prices[0]

    let ans = 0

    for (const price of prices) { 
        ans = Math.max(ans, price - min)
        min = Math.min(min, price)
    }

    return ans
};

三数之和

https://leetcode.cn/problems/3sum/description/ #双指针

这里我在实现的时候是选了一个数,然后去找它后面的数。如果我选择一个数,去找它前面一个、后面一个数会怎么样呢?

function threeSum(nums: number[]): number[][] {
    // 先排序,排序后遍历每一项
    nums.sort((a, b) => a - b)
    const ans = []
    const n = nums.length

    for (let i = 0; i < n - 2; i++) {
        const x = nums[i]

        // 如果当前项和上一项是一样的,那么他们形成的答案肯定是一样的,所以跳过
        if (i > 0 && x === nums[i - 1]) continue

        // 初始化j与k的位置
        let j = i + 1
        let k = n - 1

        while (j < k) {
            let s = x + nums[j] + nums[k]
            if (s > 0) {
                k--
            } else if (s < 0) {
                j++
            } else {
                ans.push([x, nums[j], nums[k]])

                // 这里也是为了保证j与k是不一样的
                j++
                while (j < k && nums[j] === nums[j - 1]) { j++ }

                k--
                while (j < k && nums[k] === nums[k + 1]) { k-- }
            }
        }
    }

    return ans
};

146 LRU缓存机制

https://leetcode.cn/problems/lru-cache/description/


141 环形链表


112 路径总和

#链表 https://leetcode.cn/problems/path-sum/ 这道没做过

function hasPathSum(root: TreeNode | null, targetSum: number): boolean {
    if (root === null) return false

    targetSum -= root.val

	// 这种情况下,是叶子节点,就直接返回结果
    if (root.left === null && root.right === null) return targetSum === 0

	// 这种情况下的话,就是原问题类似的子问题,递归的调用
    return hasPathSum(root.left, targetSum) || hasPathSum(root.right, targetSum)
};

21 合并两个有序链表


215 数组中的第K大

https://leetcode.cn/problems/kth-largest-element-in-an-array/description/ 在数组中,随机的选一个数,以它为准,将小于的放在其左侧,大于的在右侧,如果这个数正好是第k个,那么他就是第k大,如果不是,那就在左右两侧继续找


912 快排

https://leetcode.cn/problems/sort-an-array/solutions/3799866/onlogn-kuai-su-pai-xu-fen-zhi-xie-fa-you-njpq/

// 在子数组 [left, right] 中随机选择一个基准元素 pivot
// 根据 pivot 重新排列子数组 [left, right]
// 重新排列后,<= pivot 的元素都在 pivot 的左侧,>= pivot 的元素都在 pivot 的右侧
// 返回 pivot 在重新排列后的 nums 中的下标
// 特别地,如果子数组的所有元素都等于 pivot,我们会返回子数组的中心下标,避免退化
function partition(nums, left, right) {
    // 1. 在子数组 [left, right] 中随机选择一个基准元素 pivot
    const idx = left + Math.floor(Math.random() * (right - left + 1));
    const pivot = nums[idx];
    // 把 pivot 与子数组第一个元素交换,避免 pivot 干扰后续划分,从而简化实现逻辑
    [nums[idx], nums[left]] = [nums[left], nums[idx]];

    // 2. 相向双指针遍历子数组 [left + 1, right]
    // 循环不变量:在循环过程中,子数组的数据分布始终如下图
    // [ pivot | <=pivot | 尚未遍历 | >=pivot ]
    //   ^                 ^     ^         ^
    //   left              i     j         right

    let i = left + 1, j = right;
    while (true) {
        while (i <= j && nums[i] < pivot) {
            i++;
        }
        // 此时 nums[i] >= pivot

        while (i <= j && nums[j] > pivot) {
            j--;
        }
        // 此时 nums[j] <= pivot

        if (i >= j) {
            break;
        }

        // 维持循环不变量
        [nums[i], nums[j]] = [nums[j], nums[i]];
        i++;
        j--;
    }

    // 循环结束后
    // [ pivot | <=pivot | >=pivot ]
    //   ^             ^   ^     ^
    //   left          j   i     right

    // 3. 把 pivot 与 nums[j] 交换,完成划分(partition)
    // 为什么与 j 交换?
    // 如果与 i 交换,可能会出现 i = right + 1 的情况,已经下标越界了,无法交换
    // 另一个原因是如果 nums[i] > pivot,交换会导致一个大于 pivot 的数出现在子数组最左边,不是有效划分
    // 与 j 交换,即使 j = left,交换也不会出错
    [nums[left], nums[j]] = [nums[j], nums[left]];

    // 返回 pivot 的下标
    return j;
}

// 快速排序子数组 [left, right]
function quickSort(nums, left, right) {
    // 优化:如果子数组已是升序,直接返回
    let ordered = true;
    for (let i = left; i < right; i++) {
        if (nums[i] > nums[i + 1]) {
            ordered = false;
            break;
        }
    }
    if (ordered) {
        return;
    }

    const i = partition(nums, left, right); // 划分子数组
    quickSort(nums, left, i - 1);  // 排序在 pivot 左侧的元素
    quickSort(nums, i + 1, right); // 排序在 pivot 右侧的元素
}

var sortArray = function(nums) {
    quickSort(nums, 0, nums.length - 1);
    return nums;
};

5 最长回文子串 ⌚️

https://leetcode.cn/problems/longest-palindromic-substring/


70 爬楼梯

https://leetcode.cn/problems/climbing-stairs/ f(n) = f(n - 1) + f(n - 2)

/**
 * @param {number} n
 * @return {number}
 */
const map = new Map()
var climbStairs = function (n) {
    if (n === 0 || n === 1) {
        return 1
    } else if (n === 2) {
        return 2
    }

    if (map.has(n)) {
        console.log('has', map.get(n))

        return map.get(n)
    } else {
        const temp = climbStairs(n - 1) + climbStairs(n - 2)
        map.set(n, temp)
        return temp
    }
}

54 螺旋矩阵

https://leetcode.cn/problems/spiral-matrix/description/


200 岛屿的数量

https://leetcode.cn/problems/number-of-islands/description/


300 最长上升子序列

https://leetcode.cn/problems/longest-increasing-subsequence/description/


56 区间合并 ⌚️

https://leetcode.cn/problems/merge-intervals/submissions/662938365/ 给定一个表示若干个区间的集合数组intervals,每个区间由起始位置start和结束位置end组成。请合并所有重叠的区间,返回一个不重叠的区间数组,该数组需包含输入中的所有区间,并确保区间之间没有重叠。

我写的一大坨:

function fn(arr1, arr2) {
    console.log(arr1, arr2);

    if (arr1[1] >= arr2[0]) {
        return true
    }

    return false
}

var merge = function (intervals) {
    let ans = []

    // console.log(intervals)
    intervals.sort((a, b) => a[0] < b[0])
    // console.log(intervals)

    let min = intervals[0][0]
    let max = intervals[0][1]

    for (let i = 0; i < intervals.length - 1; i++) {
        let curArr = intervals[i]
        let nxtArr = intervals[i + 1]

        if (fn(curArr, nxtArr)) {
            min = Math.min(...curArr, ...nxtArr)
            max = Math.max(...curArr, ...nxtArr)
            console.log(fn(curArr, nxtArr), min, max, '777')
        } else {
            console.log([min, max],'666')
            ans.push([min, max])
            min = 0
            max = 0
        }
    }

    ans.push([min, max])

    return ans
}
console.log(
    merge([
        [1, 2],
        [2, 3],
        [4, 6],
        
    ]),
)
// [ 1, 2 ] [ 2, 3 ]
// [ 1, 2 ] [ 2, 3 ]
// true 1 3 777
// [ 2, 3 ] [ 4, 6 ]
// [ 1, 3 ] 666
// [ [ 1, 3 ], [ 0, 0 ] ]

参考答案:

/**
 * @param {number[][]} intervals - 输入的区间数组
 * @return {number[][]} - 合并后的区间数组
 */
var merge = function(intervals) {
    // 1. 边界处理:如果数组为空或长度小于2,无需合并
    if (!intervals || intervals.length < 2) {
        return intervals;
    }
	
    // 2. 排序:按照区间的起始位置(start)进行升序排序
    // a[0] 代表当前区间的 start,b[0] 代表下一个区间的 start
    intervals.sort((a, b) => a[0] - b[0]);
	
    // 3. 初始化结果数组,先放入第一个区间
    const merged = [intervals[0]];
	
    // 4. 遍历剩余的区间
    for (let i = 1; i < intervals.length; i++) {
        const currentInterval = intervals[i];
        
        // 获取结果数组中最后一个区间(即当前正在构建的合并区间)
        const lastMergedInterval = merged[merged.length - 1];
		
        // 5. 判断是否重叠
        // 如果当前区间的 start <= 上一个合并区间的 end,说明有重叠
        if (currentInterval[0] <= lastMergedInterval[1]) {
            // 合并操作:更新上一个合并区间的 end 为两者的最大值
            // Math.max 确保我们取到最远的结束点(例如 [1, 10] 和 [2, 6] 合并应为 [1, 10])
            lastMergedInterval[1] = Math.max(lastMergedInterval[1], currentInterval[1]);
        } else {
            // 6. 无重叠:直接将当前区间推入结果数组
            merged.push(currentInterval);
        }
    }

    return merged;
};

![Pasted image 20260608172622](../../../../_assets/d75f4f9-Pasted image 20260608172622.png) 我还做过呢,艹了。这肯定是没了啊,这题都没搞出来,你。。。这道好像是美团的,挂了已经


704 二分查找

https://leetcode.cn/problems/binary-search/description/

function search(nums: number[], target: number): number {
    const n = nums.length
    let left = 0
    let right = n - 1

    while (left <= right) {
        let mid = Math.floor((left + right) / 2)
        if(nums[mid] === target){
            return mid
        }else if(nums[mid] > target){
            right = mid - 1
        }else{
            left = mid + 1
        }
    }

    return -1
};

129 求根到叶子节点的路径值和

https://leetcode.cn/problems/sum-root-to-leaf-numbers/description/

var sumNumbers = function(root, x = 0) {
    if (root === null) {
        return 0;
    }
    x = x * 10 + root.val;
    if (root.left === null && root.right === null) { // root 是叶子节点
        return x;
    }
    return sumNumbers(root.left, x) + sumNumbers(root.right, x);
};

93 复原IP地址

https://leetcode.cn/problems/restore-ip-addresses/

function restoreIpAddresses(s: string): string[] {
    // 这题的本质是选.合理的位置
    let n = s.length
    let ans = []
    let path = []
	
    if (n < 4 || n > 12) return ans
	
    // 表示从i开始进行划分的所有可能性
    function dfs(i) {
        if (path.length === 3) {
            // 1. 获取最后一段字符串
            const lastSegment = s.slice(i)
            
            // 2. 对最后一段进行合法性校验
            // 长度不能超过3
            if (lastSegment.length > 3) return 
            // 不能有前导零(长度大于1且首位是'0')
            if (lastSegment.length > 1 && lastSegment[0] === '0') return 
            // 数值不能大于255
            if (Number(lastSegment) > 255) return 
			
            ans.push(`${s.slice(0, path[0])}.${s.slice(path[0], path[1])}.${s.slice(path[1], path[2])}.${s.slice(path[2])}`)
            return
        }
		
        for (const len of [1, 2, 3]) {
            if (i + len > n) break
            if (len > 1 && s[i] === '0') break
            if (Number(s.slice(i, i + len)) > 255) break
			
            const remainingSegments = 3 - path.length;
            const remainingChars = n - (i + len);
            if (remainingChars < remainingSegments || remainingChars > remainingSegments * 3) {
                continue; // 当前长度不合适,尝试下一个长度
            }
            path.push(i + len)
            dfs(i + len)
            path.pop()
			
        }
    }
    dfs(0)
    return ans
}

322 零钱兑换

https://leetcode.cn/problems/coin-change/description/


104 二叉树的最大深度

https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/


22 括号生成

https://leetcode.cn/problems/generate-parentheses/description/


LCR 126 斐波那契数列

https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof/description/

function fib(n: number): number {
    const mod = Math.pow(10, 9) + 7
    const map = new Map<number, number>()

    const helper = (n: number): number => {
        if (n === 0) return 0
        if (n === 1) return 1

        if (map.has(n)) return map.get(n)

        // 核心改造:在相加的同时就进行取模,防止中间结果溢出
        const ans = (helper(n - 1) + helper(n - 2)) % mod

        map.set(n, ans)
        return ans
    };

    return helper(n)
}

695 岛屿的最大面积

https://leetcode.cn/problems/max-area-of-island/

function maxAreaOfIsland(grid: number[][]): number {
    const n = grid.length
    const m = grid[0].length

    let ans = 0

    // 这个函数的作用是将包含i, j坐标的岛屿的面积找出来
    const dfs = (i, j) => {
        // 如果是越界或者不是岛屿(海洋、遍历过的岛)
        if (i >= n || i < 0 || j >= m || j < 0 || grid[i][j] !== 1) return 0

        // 标记岛屿
        grid[i][j] = 2

        // 递归调用
        return dfs(i - 1, j) + dfs(i, j - 1) + dfs(i + 1, j) + dfs(i, j + 1) + 1
    }

    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            ans = Math.max(dfs(i, j), ans)
            console.log(i, j, dfs(i, j),ans)
        }
    }

    console.log(grid)
    return ans
};

LCR 140 训练计划 II

#双指针 https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/

灵神的脑子怎么这么聪明啊

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

var trainingPlan = function(head, k) {
    let left = head, right = head;
    while (k--) right = right.next; // 右指针先向右走 k 步
    // 然后左右指针一起走,右指针走到空节点时,左指针正好就在倒数第 k 个节点
    while (right) {
        left = left.next;
        right = right.next;
    }
    return left;
};

94 二叉树的中序遍历

左跟右


42 接雨水

#双指针 https://leetcode.cn/problems/trapping-rain-water/description/

使用前缀最大值与后缀最大值来标记:

function trap(height: number[]): number {
    let ans = 0

    const n = height.length
    const preMax = Array(n)  
    const sufMax = Array(n)

    preMax[0] = height[0]
    for (let i = 1; i < n; i++) {
        preMax[i] = Math.max(preMax[i - 1], height[i])
    }

    sufMax[n - 1] = height[n - 1]
    for (let i = n - 2; i >= 0; i--) {
        sufMax[i] = Math.max(sufMax[i + 1], height[i])
    }

    for (let i = 0; i < n; i++) {
        ans += Math.min(preMax[i], sufMax[i]) - height[i]
    }

    console.log(preMax, sufMax)
    return ans
};

1143 最长公共子序列

#动态规划 https://leetcode.cn/problems/longest-common-subsequence/description/

function longestCommonSubsequence(text1: string, text2: string): number {
    let m = text1.length
    let n = text2.length

    // dfs(i, j)表示以text1[i]与text2[j]结尾的两个子串的最长公共子序列
    const memo = new Array(m).fill('').map(i => new Array(n).fill(-1))

    const dfs = (i, j) => {
        if (i < 0 || j < 0) return 0

        if (memo[i][j] !== -1) return memo[i][j]
        if (text1[i] === text2[j]) {
            memo[i][j] = dfs(i - 1, j - 1) + 1
            return memo[i][j]
        }

        memo[i][j] = Math.max(dfs(i - 1, j), dfs(i, j - 1))

        return memo[i][j]
    }

    return dfs(m - 1, n - 1)
};

14 最长公共前缀


226 翻转二叉树


1556 千位分割数


62 不同路径

#动态规划 https://leetcode.cn/problems/unique-paths/submissions/728284503/

function uniquePaths(m: number, n: number): number {
    const memo = new Array(m).fill('').map(i => new Array(n).fill(-1))
    console.log(memo)
	
    const dfs = (i, j) => {
        console.log(i,j)
        if (i < 0 || j < 0) return 0
        if (i === 0 && j === 0) return 1
        if (memo[i][j] !== -1) return memo[i][j]
		
        let ans = dfs(i - 1, j) + dfs(i, j - 1)
        memo[i][j] = ans
        return ans
    }
    return dfs(m - 1, n - 1)
};

25 K个一组反转链表

这道题我认为在前端就几乎不会考了。。。


283 移动零

https://leetcode.cn/problems/move-zeroes/description/ 简单来讲,就是将非零的元素全部都移动到数组的前面,再根据数组中非零元素的个数与数组的长度,将剩余的零补上就可以了

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var moveZeroes = function (nums) {
    let stackSize = 0
    // 遍历每一个元素,如果非零就直接进入数组(可能会覆盖掉自己)
    // 0的位置不用考虑,等所有的非零元素进入后,再将0填入
    for (const num of nums) {
        if (num !== 0) {
            nums[stackSize] = num
            stackSize++
        }
    }
    nums.fill(0, stackSize)
}

236 二叉树的最近公共祖先

没看懂哈。。。

答案只有两种情况:

  • 这两个点是某个节点的子孙。直接返回,因为下面肯定没有,在另一个子树上。
  • 这两个点互为爷孙。那么遍历到这两个点就可以直接返回了,应为爷爷就是答案
var lowestCommonAncestor = function(root, p, q) {
    if (root === null || root === p || root === q) {
        return root; // 找到 p 或 q 就不往下递归了,原因见上面答疑
    }
    const left = lowestCommonAncestor(root.left, p, q);
    const right = lowestCommonAncestor(root.right, p, q);
    if (left && right) { // 左右都找到
        return root; // 当前节点是最近公共祖先
    }
    // 如果只有左子树找到,就返回左子树的返回值
    // 如果只有右子树找到,就返回右子树的返回值
    // 如果左右子树都没有找到,就返回 null(注意此时 right = null)
    return left ?? right;
};

103 二叉树的锯齿形层序遍历

https://leetcode.cn/problems/binary-tree-zigzag-level-order-traversal/description/

这道题和深度遍历很像


199 二叉树的右视图

https://leetcode.cn/problems/binary-tree-right-side-view/description/ 套用 102 题的 BFS 模板,把每一层的最后一个节点值保存到答案中。


2 两数相加

https://leetcode.cn/problems/add-two-numbers/description/

/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var addTwoNumbers = function (l1, l2, carry=0) {
    if (l1 === null && l2 === null && carry === 0) {
        return null
    }

    let sum = carry;
    if (l1) {
        sum += l1.val;
        l1=l1.next
    }
    if (l2) {
        sum += l2.val
        l2 = l2.next
    }

    return new ListNode(sum%10,addTwoNumbers(l1,l2,Math.floor(sum/10)))
}

209 长度最小的子数组

https://leetcode.cn/problems/minimum-size-subarray-sum/description/https://www.bilibili.com/video/BV1tZ4y1q7XE?spm_id_from=333.788.recommend_more_video.1&trackid=web_related_0.router-related-2589621-48s8n.1782031683220.519&vd_source=47c9acd507be61251cd2bb730416395c

这道题的思路是不断的枚举右端点,当和大于目标值的时候,移动左端点,直到小于,然后移动右端点,再左端点:

function minSubArrayLen(target: number, nums: number[]): number {
    const n = nums.length
    let ans = n + 1
    let sum = 0
    let left = 0
    for (let right = 0; right < n; right++) {
        sum += nums[right]
        while(sum >= target){
            sum -= nums[left]
            ans = Math.min(ans, right - left +1)
            left ++
        }
    }

    return ans <= n ? ans : 0
};

125 验证回文串


394 字符串解码

https://leetcode.cn/problems/decode-string/

有点难度哈。。。

var decodeString = function(s) {
    const stack = []; // 用于模拟计算机的递归
    let res = '';
    let k = 0;
    for (const c of s) {
        if ('a' <= c && c <= 'z') {
            res += c;
        } else if ('0' <= c && c <= '9') {
            k = k * 10 + parseInt(c);
        } else if (c === '[') {
            // 模拟递归
            // 在递归之前,把当前递归函数中的局部变量 res 和 k 保存到栈中
            stack.push([res, k]);
            // 递归,初始化 res 和 k
            res = '';
            k = 0;
        } else { // ']'
            // 递归结束,从栈中恢复递归之前保存的局部变量
            const [pre_res, pre_k] = stack.pop();
            // 此时 res 是下层递归的返回值,将其重复 pre_k 次,拼接到递归前的 pre_res 之后
            res = pre_res + res.repeat(pre_k);
        }
    }
    return res;
};

101 对称二叉树


155 最小栈


43 字符串相乘


198 打家劫舍

https://leetcode.cn/problems/house-robber/description/

var rob = function(nums) {
    const n = nums.length;
    const memo = Array(n).fill(-1); // -1 表示没有计算过

    // dfs(i) 表示从 nums[0] 到 nums[i] 最多能偷多少
    function dfs(i) {
        if (i < 0) { // 递归边界(没有房子)
            return 0;
        }
        if (memo[i] !== -1) { // 之前计算过
            return memo[i];
        }
        const res = Math.max(dfs(i - 1), dfs(i - 2) + nums[i]);
        memo[i] = res; // 记忆化:保存计算结果
        return res;
    }

    return dfs(n - 1); // 从最后一个房子开始思考
};

作者:灵茶山艾府
链接:https://leetcode.cn/problems/house-robber/solutions/2102725/ru-he-xiang-chu-zhuang-tai-ding-yi-he-zh-1wt1/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

160 相交链表


718 最长重复子数组

![Pasted image 20260621171215](../../../../_assets/b76c70e-Pasted image 20260621171215.png)

var findLength = function(nums1, nums2) {
    const n = nums1.length, m = nums2.length;
    const f = Array.from({ length: n + 1 }, () => Array(m + 1).fill(0));
    let ans = 0;
    for (let i = 0; i < n; i++) {
        for (let j = 0; j < m; j++) {
            if (nums1[i] === nums2[j]) {
                f[i + 1][j + 1] = f[i][j] + 1;
                ans = Math.max(ans, f[i + 1][j + 1]);
            }
        }
    }
    return ans;
};

作者:灵茶山艾府
链接:https://leetcode.cn/problems/maximum-length-of-repeated-subarray/solutions/866328/on-hou-zhui-shu-zu-by-endlesscheng-jwr2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

122 买股票的最佳时机

> 6/21/2026 > 已经将CodeTop中频度大于10的全部搞完了,LeedCode100也是,